// 增加了滑动条，用户可以进行视频跳转
// 实现了更多控制，用户通过按下S键来执行单步模式，以及按下R键来恢复连续视频播放模式
// 无论何时用户通过滑动条跳转到视频一个新的时间点，我们都会使用单步模式在那个点进行播放

// 要创建一个滑动条，我们会调用cv::createTrackbar()并指明要在哪个窗口进行显示
// 为了完成所需要的功能，我们还需要一个能够执行重新定位的回调函数

// 变量前g_表明这是一个全局变量

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <fstream>
//In genaral, 代码中添加了一个全局变量来表示滑动条的位置并且添加一个回调函数来更改这个变量重新定位视频读取的位置

// 定义一个全局变量g_slider_position来表示滑动条的位置
int g_slider_position = 0;

// 全局变量g_run将在新的跳转触发之后置0，当它为正的时候，指示在停止之前要播放多少张图片；当它为负的时候，表示系统处于连续视频播放模式
// 为了防止冲突，在用户单击了滑动条跳转到一个视频的新位置之后，我们将会通过设置g_run变量为1使视频进入单步模式
// g_dontset用来避免调整进度条位置的时候触发单步模式
int g_run = 1, g_dontset = 0; //start out in single step mode

// 由于回调函数需要访问帧读取结构g_cap，所以我们最好将这个结构也提升为全局变量
cv::VideoCapture g_cap;

// 添加一个回调函数来更改这个变量，重新定位视频读取的位置
// 程序将会传入一个32位的整型数值以表示当前的位置，这将会是进度条存在的新的位置
void onTrackbarSlide(int pos, void *)
{
    // 在新的位置通过调用g_cap.set()来真正使进度条移动到我们希望的位置
    // cv::CAP_PROP_POS_FRAMES指示我们想要帧集合的读取位置
    g_cap.set(cv::CAP_PROP_POS_FRAMES, pos);

    // if语句设置程序是否进入单步模式，只有在用户触发滑动条事件的时候，这个设置才会生效；在系统自动调用该回调函数的时候，单步模式不会生效
    if (!g_dontset)
        g_run = 1;
    g_dontset = 0;
}

int main(int argc, char **argv)
{
    cv::namedWindow("Example2_4", cv::WINDOW_AUTOSIZE);
    g_cap.open(std::string(argv[1]));

    // 打开视频之后，我们用g_cap.get()来确定总帧数以及视频的高和宽
    int frames = (int)g_cap.get(cv::CAP_PROP_FRAME_COUNT);
    int tmpw = (int)g_cap.get(cv::CAP_PROP_FRAME_WIDTH);
    int tmph = (int)g_cap.get(cv::CAP_PROP_FRAME_HEIGHT);
    std::cout << "Video has" << frames << "frames of dimensions(" << tmpw << ", " << tmph << ")." << std::endl;
    // 创建一个滑动条，cv::createTrackbar()允许我们给滑动条一个标签名称“position”，并指明在哪一个窗口放置我们的滑动条
    // 我们提供一个和滑动条绑定的变量——滑动条能够达到的最大值（视频的总帧数）以及一个在滑动条移动时候的回调函数（不需要的时候也可以输入NULL）
    cv::createTrackbar("Position", "Example2_4", &g_slider_position, frames, onTrackbarSlide);

    cv::Mat frame;

    for (;;)
    {
        if (g_run != 0)
        {
            g_cap >> frame;
            if (frame.empty())
                break;
            int current_pos = (int)g_cap.get(cv::CAP_PROP_POS_FRAMES);
            g_dontset = 1;
            // 更新滑动块在滑动条上的位置以便显示给用户
            cv::setTrackbarPos("Position", "Example2_4", current_pos);
            cv::imshow("Example2_4", frame);

            g_run -= 1;
        }

        char c = (char)cv::waitKey(10);
        if (c == 's') //single step
        {
            g_run = 1;
            std::cout << "Single step, run = " << g_run << std::endl;
        }
        if (c == 'r') //run step
        {
            g_run = -1;
            std::cout << "run step, run = " << g_run << std::endl;
        }
        if (c == 27) //single step
        {
            break;
        }
    }
    cv::destroyWindow("Example2_4");
    return (0);
}